package pl.jtb.ctl.tabory.ui.boe.ui.te;

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.DateTime;
import org.eclipse.swt.widgets.Dialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.forms.widgets.FormToolkit;

import pl.jtb.ctl.tabory.dao.data.vo.CompositionVO;
import pl.jtb.ctl.tabory.dao.data.vo.StationVO;
import pl.jtb.ctl.tabory.dao.data.vo.TripVO;
import pl.jtb.ctl.tabory.dao.impl.mybatis.servicemanager.ServiceManager;
import pl.jtb.ctl.tabory.ui.boe.osgi.Activator;

public class TripDialog extends Dialog {

    private final static Logger log = Logger.getLogger(TripDialog.class);

    protected Shell shell;
    private final FormToolkit formToolkit = new FormToolkit(Display.getDefault());
    private Button okButton;
    private Button cancelButton;

    private List<CompositionVO> listComposition;
    private List<StationVO> listStation;
    private Map<StationVO, Map<StationVO, Double>> mapDistances;
    private CompositionVO selectedComposition;
    private TripVO trip;
    private int result = Window.CANCEL;

    private Text fieldDistance;
    private Combo fieldComposition;
    private DateTime fieldDateFrom;
    private DateTime fieldDateUntil;
    private Combo fieldStationFrom;
    private Combo fieldStationTo;
    private DateTime fieldTimeFrom;
    private DateTime fieldTimeUntil;

    public TripDialog(Shell parent, Map<StationVO, Map<StationVO, Double>> mapDistances, List<CompositionVO> listComposition, List<StationVO> listStation, TripVO trip, CompositionVO selectedComposition) {
        super(parent, SWT.TITLE | SWT.BORDER | SWT.APPLICATION_MODAL);
        this.listComposition = listComposition;
        this.listStation = listStation;
        this.mapDistances = mapDistances;
        this.trip = trip;
        this.selectedComposition = selectedComposition;
        if (trip == null) {
            setText(Activator.getMessage("trip.editor.dialog.new.title"));
        } else {
            setText(Activator.getMessage("trip.editor.dialog.edit.title"));
        }
    }

    public int open() {
        createContents();
        fillContents();
        shell.open();
        shell.layout();
        Display display = getParent().getDisplay();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
        return result;
    }

    private void storeValue() throws Exception {
        if (trip == null) {
            trip = new TripVO();
        }
        trip.setComposition(listComposition.get(fieldComposition.getSelectionIndex()));
        trip.setStationFrom(fieldStationFrom.getSelectionIndex() == -1 ? null : listStation.get(fieldStationFrom.getSelectionIndex()));
        trip.setStationTo(fieldStationTo.getSelectionIndex() == -1 ? null : listStation.get(fieldStationTo.getSelectionIndex()));
        trip.setDistanceKm(Double.parseDouble(fieldDistance.getText()));
        Calendar startCalendar = new GregorianCalendar();
        startCalendar.set(Calendar.YEAR, fieldDateFrom.getYear());
        startCalendar.set(Calendar.MONTH, fieldDateFrom.getMonth());
        startCalendar.set(Calendar.DAY_OF_MONTH, fieldDateFrom.getDay());
        startCalendar.set(Calendar.HOUR_OF_DAY, fieldTimeFrom.getHours());
        startCalendar.set(Calendar.MINUTE, fieldTimeFrom.getMinutes());
        startCalendar.set(Calendar.SECOND, fieldTimeFrom.getSeconds());
        Calendar endCalendar = new GregorianCalendar();
        endCalendar.set(Calendar.YEAR, fieldDateUntil.getYear());
        endCalendar.set(Calendar.MONTH, fieldDateUntil.getMonth());
        endCalendar.set(Calendar.DAY_OF_MONTH, fieldDateUntil.getDay());
        endCalendar.set(Calendar.HOUR_OF_DAY, fieldTimeUntil.getHours());
        endCalendar.set(Calendar.MINUTE, fieldTimeUntil.getMinutes());
        endCalendar.set(Calendar.SECOND, fieldTimeUntil.getSeconds());
        trip.setListVagons(ServiceManager.getInstance().getCompositionService().getCompositionVagonRelation(trip.getComposition()).get(trip.getComposition()));
        trip.setDateUntil(endCalendar.getTime());
        trip.setDateFrom(startCalendar.getTime());
    }

    private void createContents() {
        shell = new Shell(getParent(), getStyle());
        shell.setSize(300, 260);
        shell.setText(getText());
        shell.setLayout(new GridLayout(1, false));

        Form form = formToolkit.createForm(shell);
        form.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
        formToolkit.paintBordersFor(form);
        form.getBody().setLayout(new GridLayout(3, false));

        formToolkit.createLabel(form.getBody(), Activator.getMessage("trip.editor.dialog.newedit.label.composition"), SWT.NONE);

        fieldComposition = new Combo(form.getBody(), SWT.READ_ONLY);
        fieldComposition.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1));
        fieldComposition.setEnabled(false);
        formToolkit.adapt(fieldComposition);
        formToolkit.paintBordersFor(fieldComposition);

        formToolkit.createLabel(form.getBody(), Activator.getMessage("trip.editor.dialog.newedit.label.datefrom"), SWT.NONE);

        fieldDateFrom = new DateTime(form.getBody(), SWT.DROP_DOWN | SWT.BORDER);
        formToolkit.adapt(fieldDateFrom);
        formToolkit.paintBordersFor(fieldDateFrom);

        fieldTimeFrom = new DateTime(form.getBody(), SWT.BORDER | SWT.TIME);
        formToolkit.adapt(fieldTimeFrom);
        formToolkit.paintBordersFor(fieldTimeFrom);

        formToolkit.createLabel(form.getBody(), Activator.getMessage("trip.editor.dialog.newedit.label.dateuntil"), SWT.NONE);

        fieldDateUntil = new DateTime(form.getBody(), SWT.DROP_DOWN | SWT.BORDER);
        formToolkit.adapt(fieldDateUntil);
        formToolkit.paintBordersFor(fieldDateUntil);

        fieldTimeUntil = new DateTime(form.getBody(), SWT.BORDER | SWT.TIME);
        formToolkit.adapt(fieldTimeUntil);
        formToolkit.paintBordersFor(fieldTimeUntil);

        formToolkit.createLabel(form.getBody(), Activator.getMessage("trip.editor.dialog.newedit.label.stationfrom"), SWT.NONE);

        fieldStationFrom = new Combo(form.getBody(), SWT.READ_ONLY);
        fieldStationFrom.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1));
        formToolkit.adapt(fieldStationFrom);
        formToolkit.paintBordersFor(fieldStationFrom);
        fieldStationFrom.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                fillDistance();
            }
        });

        formToolkit.createLabel(form.getBody(), Activator.getMessage("trip.editor.dialog.newedit.label.stationto"), SWT.NONE);

        fieldStationTo = new Combo(form.getBody(), SWT.READ_ONLY);
        fieldStationTo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1));
        formToolkit.adapt(fieldStationTo);
        formToolkit.paintBordersFor(fieldStationTo);
        fieldStationTo.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                fillDistance();
            }
        });

        formToolkit.createLabel(form.getBody(), Activator.getMessage("trip.editor.dialog.newedit.label.distance"), SWT.NONE);

        fieldDistance = new Text(form.getBody(), SWT.BORDER);
        fieldDistance.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1));
        formToolkit.adapt(fieldDistance, true, true);

        Label label = new Label(form.getBody(), SWT.SEPARATOR | SWT.HORIZONTAL);
        label.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, true, 3, 1));
        formToolkit.adapt(label, true, true);

        Composite composite = formToolkit.createComposite(form.getBody(), SWT.NONE);
        composite.setLayout(new GridLayout(3, false));
        composite.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, false, 3, 1));
        formToolkit.paintBordersFor(composite);

        Label spacer = formToolkit.createLabel(composite, "", SWT.NONE);
        spacer.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));

        okButton = formToolkit.createButton(composite, Activator.getMessage("common.save"), SWT.NONE);
        okButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                try {
                    storeValue();
                } catch (Exception e1) {
                    log.error(e1.getMessage(), e1);
                    ErrorDialog errorDialog = new ErrorDialog(shell, Activator.getMessage("common.dialog.error.title"), e1.getMessage(), new Status(1, "edytor", e1.getMessage()), 1);
                    errorDialog.open();
                }
                result = Window.OK;
                shell.dispose();
            }
        });

        cancelButton = formToolkit.createButton(composite, Activator.getMessage("common.cancel"), SWT.NONE);
        cancelButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                shell.dispose();
            }
        });

        fieldDateFrom.setFocus();
    }

    private void fillContents() {
        for (CompositionVO composition : listComposition) {
            fieldComposition.add(composition.getInternalId());
        }
        for (StationVO station : listStation) {
            fieldStationFrom.add(station.getStationName());
            fieldStationTo.add(station.getStationName());
        }
        if (trip != null) {
            Calendar startCalendar = new GregorianCalendar();
            startCalendar.setTime(trip.getDateFrom());
            Calendar untilCalendar = new GregorianCalendar();
            untilCalendar.setTime(trip.getDateFrom());
            fieldDateFrom.setDay(startCalendar.get(Calendar.DAY_OF_MONTH));
            fieldDateFrom.setMonth(startCalendar.get(Calendar.MONTH));
            fieldDateFrom.setYear(startCalendar.get(Calendar.YEAR));
            fieldTimeFrom.setHours(startCalendar.get(Calendar.HOUR_OF_DAY));
            fieldTimeFrom.setMinutes(startCalendar.get(Calendar.MINUTE));
            fieldTimeFrom.setSeconds(startCalendar.get(Calendar.SECOND));
            fieldDateUntil.setDay(untilCalendar.get(Calendar.DAY_OF_MONTH));
            fieldDateUntil.setMonth(untilCalendar.get(Calendar.MONTH));
            fieldDateUntil.setYear(untilCalendar.get(Calendar.YEAR));
            fieldTimeUntil.setHours(untilCalendar.get(Calendar.HOUR_OF_DAY));
            fieldTimeUntil.setMinutes(untilCalendar.get(Calendar.MINUTE));
            fieldTimeUntil.setSeconds(untilCalendar.get(Calendar.SECOND));
            fieldDistance.setText(String.valueOf(trip.getDistanceKm()));
            StationVO stationFrom = trip.getStationFrom();
            StationVO stationTo = trip.getStationTo();
            int stationFromIndex = -1;
            int stationToIndex = -1;
            if (stationTo != null) {
                for (StationVO station : listStation) {
                    if (station.getStationName().equals(stationTo.getStationName())) {
                        stationToIndex = listStation.indexOf(station);
                        break;
                    }
                }
            }
            if (stationFrom != null) {
                for (StationVO station : listStation) {
                    if (station.getStationName().equals(stationFrom.getStationName())) {
                        stationFromIndex = listStation.indexOf(station);
                        break;
                    }
                }
            }
            fieldStationFrom.select(stationFromIndex);
            fieldStationTo.select(stationToIndex);
        } else {
            fieldStationFrom.select(0);
            fieldStationTo.select(0);
            fieldDistance.setText("0.0");
        }
        int compositionIndex = -1;
        if (selectedComposition != null) {
            for (CompositionVO vo : listComposition) {
                if (vo.getInternalId().equals(selectedComposition.getInternalId())) {
                    compositionIndex = listComposition.indexOf(vo);
                    break;
                }
            }
        }
        fieldComposition.select(compositionIndex);
    }

    public TripVO getValue() {
        return trip;
    }

    private void fillDistance() {
        if (fieldStationFrom.getSelectionIndex() != -1 && fieldStationTo.getSelectionIndex() != -1) {
            StationVO stationFrom = listStation.get(fieldStationFrom.getSelectionIndex());
            StationVO stationTo = listStation.get(fieldStationTo.getSelectionIndex());
            Double distance = mapDistances.get(stationFrom).get(stationTo);
            fieldDistance.setText(String.valueOf(distance));
        }
    }

}
